package top.hcode.hoj.manager.org;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.BooleanUtil;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils;
import org.nutz.lang.Lang;
import org.nutz.lang.Strings;
import org.springframework.stereotype.Component;
import top.hcode.hoj.common.exception.StatusFailException;
import top.hcode.hoj.dao.org.OrgUserDao;
import top.hcode.hoj.dao.user.SessionEntityService;
import top.hcode.hoj.pojo.dto.OrgUserLoginDTO;
import top.hcode.hoj.pojo.entity.org.OrgUser;
import top.hcode.hoj.pojo.entity.user.Session;
import top.hcode.hoj.pojo.vo.OrgUserInfoVO;
import top.hcode.hoj.shiro.AccountProfile;
import top.hcode.hoj.utils.Constants;
import top.hcode.hoj.utils.IpUtils;
import top.hcode.hoj.utils.JwtUtils;
import top.hcode.hoj.utils.RedisUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author orangej
 * @since 2025/1/21
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class OrgUserManager {
    private final JwtUtils jwtUtils;
    private final RedisUtils redisUtils;
    private final OrgUserDao orgUserDao;
    private final SessionEntityService sessionEntityService;

    public OrgUserInfoVO login(OrgUserLoginDTO loginDto, HttpServletRequest request, HttpServletResponse response) throws StatusFailException {
        // 去掉账号密码首尾的空格
        String realName = loginDto.getRealName().trim();
        String username = Strings.trim(loginDto.getUsername());
        String mobile = Strings.trim(loginDto.getMobile());

        String userIpAddr = IpUtils.getUserIpAddr(request);
        String key = Constants.Account.TRY_LOGIN_NUM.getCode() + loginDto.getUsername() + "_" + userIpAddr;
        Integer tryLoginCount = (Integer) redisUtils.get(key);

        if (tryLoginCount != null && tryLoginCount >= 20) {
            throw new StatusFailException("对不起！登录失败次数过多！您的账号有风险，半个小时内暂时无法登录！");
        }

        OrgUser orgUser = orgUserDao.getByUsernameOrMobile(username, mobile);
        if (orgUser == null) {
            throw new StatusFailException("用户名或密码错误！请注意大小写！");
        }

        // 判断用户类型
        Integer userType = loginDto.getUserType();
        if (userType != null && !userType.equals(orgUser.getUserType())) {
            String typeName = Constants.UserType.getUserType(userType).name();
            throw new StatusFailException("用户类型不匹配，请使用" + typeName + "用户登录");
        }

        if (!orgUser.getRealName().equals(realName)) {
            if (tryLoginCount == null) {
                redisUtils.set(key, 1, 60 * 30); // 三十分钟不尝试，该限制会自动清空消失
            } else {
                redisUtils.set(key, tryLoginCount + 1, 60 * 30);
            }
            throw new StatusFailException("用户名或密码错误！请注意大小写！");
        }

        if (!BooleanUtil.isTrue(orgUser.getEnabled())) {
            throw new StatusFailException("该账户已被封禁，请联系管理员进行处理！");
        }

        String jwt = jwtUtils.generateToken(orgUser.getId());
        response.setHeader("Authorization", jwt); //放到信息头部
        response.setHeader("Access-Control-Expose-Headers", "Authorization");

        // 会话记录
        sessionEntityService.save(new Session()
                .setUid(orgUser.getId())
                .setIp(IpUtils.getUserIpAddr(request))
                .setUserAgent(request.getHeader("User-Agent")));

        // 登录成功，清除锁定限制
        if (tryLoginCount != null) {
            redisUtils.del(key);
        }

        // 异步检查是否异地登录
//        sessionEntityService.checkRemoteLogin(userRolesVo.getUid());

        OrgUserInfoVO userInfoVo = new OrgUserInfoVO();
        BeanUtil.copyProperties(orgUser, userInfoVo);
        userInfoVo.setUid(orgUser.getId());
        userInfoVo.setAvatar(orgUser.getAvatar());
        userInfoVo.setRealname(orgUser.getRealName());

        // student or teacher role
        boolean isStudent = Constants.UserType.STUDENT.getType().equals(orgUser.getUserType());
        String role = isStudent ? "student" : "teacher";
        userInfoVo.setRoleList(Lang.list(role));

        // 设置班级名称
        if (isStudent) {
            userInfoVo.setClassName(orgUserDao.getStudentClassName(orgUser.getId()));
        }
        return userInfoVo;
    }

    public void logout() {
        AccountProfile userRolesVo = (AccountProfile) SecurityUtils.getSubject().getPrincipal();
        if (userRolesVo != null) {
            jwtUtils.cleanToken(userRolesVo.getUid());
            SecurityUtils.getSubject().logout();
        }
    }

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            System.out.println(IdWorker.getIdStr());
        }
    }
}
